package com.bee.dao;

import java.sql.Connection;
import java.sql.ParameterMetaData;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.beanutils.BeanUtils;

import com.bee.utils.JdbcUtil;

/**
 * DAO的通用封装实现代码复用
 * 
 * @author beeworkshop
 *
 */
public class BaseDaoImpl implements BaseDao {

	// DML通用封装（insert，delete，update）
	@Override
	public int execUpdate(String sql, Object[] params) {
		Connection conn = null;
		PreparedStatement ps = null;
		int rows = 0;
		try {
			conn = JdbcUtil.getConnection();
			conn.setAutoCommit(false);
			ps = conn.prepareStatement(sql);
			// 得到参数的个数
			ParameterMetaData pmd = ps.getParameterMetaData();
			// 绑定参数
			for (int i = 0; i < pmd.getParameterCount(); i++) {
				ps.setObject(i + 1, params[i]);
			}
			rows = ps.executeUpdate();
			JdbcUtil.commit(conn);
		} catch (Exception e) {
			e.printStackTrace();
			JdbcUtil.rollback(conn);
		} finally {
			JdbcUtil.closeResource(null, ps, conn);
		}
		return rows;
	}

	/**
	 * 查询通用封装（select）
	 * 
	 * 完成通用查询的方法 <T> List<T> ：泛型方法——调用方法的时候再给具体类型。如果是类泛型，就必须在生成对象的时候指定具体的类型。
	 * 
	 * 注意：通用的查询方法中要求模型对象的属性名必须要和数据库表中的列名相同。
	 */
	@Override
	public <T> List<T> find(String sql, Object[] params, Class<T> clazz) {
		Connection conn = null;
		PreparedStatement ps = null;
		ResultSet rs = null;
		List<T> list = new ArrayList<>();
		try {
			conn = JdbcUtil.getConnection();
			ps = conn.prepareStatement(sql);
			// 得到参数的个数
			ParameterMetaData pmd = ps.getParameterMetaData();
			// 绑定参数
			for (int i = 0; i < pmd.getParameterCount(); i++) {
				ps.setObject(i + 1, params[i]);
			}
			// 处理结果集
			rs = ps.executeQuery();
			// 获取结果集的信息
			ResultSetMetaData rsmd = rs.getMetaData();
			while (rs.next()) {
				// 完成ORM处理：通过JDK的反射
				T bean = clazz.newInstance();
				for (int i = 0; i < rsmd.getColumnCount(); i++) {
					// 得到字段名
					// 这里使用getColumnLabel()才能取到列的别名
					// 使用getColumnName()只能取到数据库表的原始列名，取不到列的别名。
					String columnName = rsmd.getColumnLabel(i + 1);
					// 获取字段值
					Object value = rs.getObject(columnName);
					// 通过BeanUtil工具类将字段值设置到对象属性中
					// 使用Apache的开源工具：commons-beanutils-1.7.0.jar
					BeanUtils.setProperty(bean, columnName, value); // 第一个参数是Object类型
				}
				list.add(bean);
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			JdbcUtil.closeResource(rs, ps, conn);
		}
		return list;
	}

}
